[ACM] Support for running unlabeled domains alongside labeled ones
authorkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Mon, 6 Aug 2007 09:10:34 +0000 (10:10 +0100)
committerkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Mon, 6 Aug 2007 09:10:34 +0000 (10:10 +0100)
Add support for running unlabeled domains alongside labeled ones, if
the policy contains a VM label with name '__UNLABELED__' and an STE
type with the same name. The ezpolicy tool has been modified to
automatically suggest a policy under which unlabeled domains can
run. The user may delete this, if this is not desired.

Signed-off-by: Stefan Berger <stefanb@us.ibm.com>
tools/python/xen/util/acmpolicy.py
tools/python/xen/util/security.py
tools/python/xen/xend/XendDomainInfo.py
tools/python/xen/xend/server/blkif.py
tools/python/xen/xm/main.py
tools/security/xensec_ezpolicy
xen/acm/acm_chinesewall_hooks.c
xen/acm/acm_simple_type_enforcement_hooks.c

index 277e6b49faac0b5abd65b54c0a68ae5f9fefc935..5577193a762868a222457aa6e502a4bb296cf622 100644 (file)
@@ -47,6 +47,9 @@ ACM_POLICY_UNDEFINED = 15
 
 ACM_SCHEMA_FILE = "/etc/xen/acm-security/policies/security_policy.xsd"
 
+ACM_LABEL_UNLABELED = "__UNLABELED__"
+ACM_LABEL_UNLABELED_DISPLAY = "unlabeled"
+
 class ACMPolicy(XSPolicy):
     """
      ACMPolicy class. Implements methods for getting information from
@@ -925,11 +928,13 @@ class ACMPolicy(XSPolicy):
             return -xsconstants.XSERR_POLICY_INCONSISTENT, "", ""
 
         vms_with_chws = []
-        chws_by_vm = {}
+        chws_by_vm = { ACM_LABEL_UNLABELED : [] }
         for v in vms:
             if v.has_key("chws"):
                 vms_with_chws.append(v["name"])
                 chws_by_vm[v["name"]] = v["chws"]
+
+
         if bootstrap in vms_with_chws:
             vms_with_chws.remove(bootstrap)
             vms_with_chws.sort()
@@ -937,12 +942,16 @@ class ACMPolicy(XSPolicy):
         else:
             vms_with_chws.sort()
 
+        if ACM_LABEL_UNLABELED in vms_with_chws:
+            vms_with_chws.remove(ACM_LABEL_UNLABELED) ; # @1
+
         vms_with_stes = []
-        stes_by_vm = {}
+        stes_by_vm = { ACM_LABEL_UNLABELED : [] }
         for v in vms:
             if v.has_key("stes"):
                 vms_with_stes.append(v["name"])
                 stes_by_vm[v["name"]] = v["stes"]
+
         if bootstrap in vms_with_stes:
             vms_with_stes.remove(bootstrap)
             vms_with_stes.sort()
@@ -950,6 +959,9 @@ class ACMPolicy(XSPolicy):
         else:
             vms_with_stes.sort()
 
+        if ACM_LABEL_UNLABELED in vms_with_stes:
+            vms_with_stes.remove(ACM_LABEL_UNLABELED) ; # @2
+
         resnames = self.policy_get_resourcelabel_names()
         resnames.sort()
         stes_by_res = {}
@@ -958,6 +970,9 @@ class ACMPolicy(XSPolicy):
             if r.has_key("stes"):
                 stes_by_res[r["name"]] = r["stes"]
 
+        if ACM_LABEL_UNLABELED in resnames:
+            resnames.remove(ACM_LABEL_UNLABELED)
+
         max_chw_ssids = 1 + len(vms_with_chws)
         max_chw_types = 1 + len(vms_with_chws)
         max_ste_ssids = 1 + len(vms_with_stes) + len(resnames)
@@ -1083,6 +1098,8 @@ class ACMPolicy(XSPolicy):
              pr_bin += "\x00"
 
         # Build chinese wall part
+        vms_with_chws.insert(0, ACM_LABEL_UNLABELED)
+
         cfses_names = self.policy_get_chwall_cfses_names_sorted()
         cfses = self.policy_get_chwall_cfses()
 
@@ -1105,9 +1122,7 @@ class ACMPolicy(XSPolicy):
                               chw_running_types_offset,
                               chw_conf_agg_offset)
         chw_bin_body = ""
-        # simulate __NULL_LABEL__
-        for c in chws:
-            chw_bin_body += struct.pack("!h",0)
+
         # VMs that are listed and their chinese walls
         for v in vms_with_chws:
             for c in chws:
@@ -1143,6 +1158,8 @@ class ACMPolicy(XSPolicy):
             chw_bin += "\x00"
 
         # Build STE part
+        vms_with_stes.insert(0, ACM_LABEL_UNLABELED) # Took out in @2
+
         steformat="!iiiii"
         ste_bin = struct.pack(steformat,
                               ACM_STE_VERSION,
@@ -1152,10 +1169,7 @@ class ACMPolicy(XSPolicy):
                               struct.calcsize(steformat))
         ste_bin_body = ""
         if stes:
-            # Simulate __NULL_LABEL__
-            for s in stes:
-                ste_bin_body += struct.pack("!h",0)
-            # VMs that are listed and their chinese walls
+            # VMs that are listed and their STE types
             for v in vms_with_stes:
                 unknown_ste |= (set(stes_by_vm[v]) - set(stes))
                 for s in stes:
index 47d51cb20aabe9f96386c1df210417026da81e88..9452687336673152a8b948f9a14caa18f66032c9 100644 (file)
@@ -155,7 +155,7 @@ def calc_dom_ssidref_from_info(info):
             ssidref = label2ssidref(vmlabel, policyname, "dom")
             return ssidref
         else:
-            return 0
+            return 0x0
     raise VmError("security.calc_dom_ssidref_from_info: info of type '%s'"
                   "not supported." % type(info))
 
@@ -232,6 +232,10 @@ def ssidref2label(ssidref_var):
     else:
         err("Instance type of ssidref not supported (must be of type 'str' or 'int')")
 
+    if ssidref == 0:
+        from xen.util.acmpolicy import ACM_LABEL_UNLABELED
+        return ACM_LABEL_UNLABELED
+
     try:
         mapfile_lock()
 
@@ -867,7 +871,7 @@ def get_domain_resources(dominfo):
                 resources[typ].append("%s:%s:%s" %
                                       (xsconstants.ACM_POLICY_ID,
                                        active_policy,
-                                       "unlabeled"))
+                                       ACM_LABEL_UNLABELED))
 
     return resources
 
index 9d57d15b33e3315f025a9cae0e7e75132f8ca74b..0d3a8ea055bd878045c17abb9cbff86b07c72a05 100644 (file)
@@ -1463,8 +1463,6 @@ class XendDomainInfo:
         ssidref = 0
         if security.on():
             ssidref = security.calc_dom_ssidref_from_info(self.info)
-            if ssidref == 0:
-                raise VmError('VM is not properly labeled.')
             if security.has_authorization(ssidref) == False:
                 raise VmError("VM is not authorized to run.")
 
index 31089b704c49703036684a56c0c90acb01ca3a7f..62512a4cd924fcf8597b2667e66a1a3a981564fd 100644 (file)
@@ -73,17 +73,7 @@ class BlkifController(DevController):
             back['uuid'] = uuid
 
         if security.on():
-            (label, ssidref, policy) = \
-                                 security.get_res_security_details(uname)
-            domain_label = self.vm.get_security_label()
-            if domain_label:
-                rc = security.res_security_check_xapi(label, ssidref, policy,
-                                                      domain_label)
-                if rc == 0:
-                    raise VmError("VM's access to block device '%s' denied." %
-                                  uname)
-            else:
-                raise VmError("VM must have a security label.")
+            self.do_access_control(config, uname)
 
         devid = blkif.blkdev_name_to_number(dev)
         if devid is None:
@@ -95,6 +85,21 @@ class BlkifController(DevController):
 
         return (devid, back, front)
 
+    def do_access_control(self, config, uname):
+        (label, ssidref, policy) = \
+                             security.get_res_security_details(uname)
+        domain_label = self.vm.get_security_label()
+        if domain_label:
+            rc = security.res_security_check_xapi(label, ssidref, policy,
+                                                  domain_label)
+            if rc == 0:
+                raise VmError("VM's access to block device '%s' denied" %
+                              uname)
+        else:
+            from xen.util.acmpolicy import ACM_LABEL_UNLABELED
+            if label != ACM_LABEL_UNLABELED:
+                raise VmError("VM must have a security label to access "
+                              "block device '%s'" % uname)
 
     def reconfigureDevice(self, _, config):
         """@see DevController.reconfigureDevice"""
index 9bd95605c72baed8de02e1b52bdf5725f371541d..59210dc526407d94f69ebe653f5960bd858ef0ec 100644 (file)
@@ -51,6 +51,7 @@ from xen.xm.opts import OptionError, Opts, wrap, set_true
 from xen.xm import console
 from xen.util.xmlrpcclient import ServerProxy
 from xen.util.security import ACMError
+from xen.util.acmpolicy import ACM_LABEL_UNLABELED_DISPLAY
 
 import XenAPI
 
@@ -947,7 +948,7 @@ def xm_label_list(doms):
         d = parse_doms_info(dom)
         if security.active_policy not in ['INACTIVE', 'NULL', 'DEFAULT']:
             if not d['seclabel']:
-                d['seclabel'] = 'ERROR'
+                d['seclabel'] = ACM_LABEL_UNLABELED_DISPLAY
         elif security.active_policy in ['DEFAULT']:
             d['seclabel'] = 'DEFAULT'
         else:
index 458ff556f210e910f88d902a50acca56a545382d..550196f77409fb435fdd1abd7fb4ea7a72cde032 100644 (file)
@@ -36,6 +36,8 @@ conflict_bmp = None
 realm_icon = None
 workload_icon = None
 
+ACM_LABEL_UNLABELED = '__UNLABELED__'
+
 class orgTreeCtrl(wx.TreeCtrl):
 
     event = None
@@ -870,7 +872,8 @@ class ezFrame(wx.Frame):
             self.realm_menu.Enable(self.ID_ORGDEL, True)
             self.realm_menu.Enable(self.ID_ORGEDT, True)
             self.realm_menu.Enable(self.ID_ORGADD, True)
-            if len(self.orgs.GetSelections()) > 1:
+            if len(self.orgs.GetSelections()) > 1 or \
+               ACM_LABEL_UNLABELED == self.orgs.GetItemText(item):
                 self.realm_menu.Enable(self.ID_ORGEDT, False)
                 self.realm_menu.Enable(self.ID_ORGADD, False)
             self.PopupMenu(self.realm_menu)
@@ -1622,6 +1625,8 @@ def main():
     app = ezApp(0)
     if len(sys.argv) in [2]:
         app.Load(sys.argv[1])
+    else:
+        dict2org({'orgs' : [[ACM_LABEL_UNLABELED,[]]], 'cons': []})
     app.MainLoop()
     print "Goodbye"
 
index 90e20a19d0a15482d4606b42e9b6ac6e2e6e8869..b05cecf9ae97969f6269b206a2e00041a7e404a7 100644 (file)
@@ -93,6 +93,7 @@ int acm_init_chwall_policy(void)
     return ACM_OK;
 }
 
+
 static int chwall_init_domain_ssid(void **chwall_ssid, ssidref_t ssidref)
 {
     struct chwall_ssid *chwall_ssidp = xmalloc(struct chwall_ssid);
@@ -104,10 +105,10 @@ static int chwall_init_domain_ssid(void **chwall_ssid, ssidref_t ssidref)
     chwall_ssidp->chwall_ssidref =
         GET_SSIDREF(ACM_CHINESE_WALL_POLICY, ssidref);
 
-    if ( (chwall_ssidp->chwall_ssidref >= chwall_bin_pol.max_ssidrefs)
-        || (chwall_ssidp->chwall_ssidref == ACM_DEFAULT_LOCAL_SSID) )
+    if ( chwall_ssidp->chwall_ssidref >= chwall_bin_pol.max_ssidrefs )
     {
-        printkd("%s: ERROR chwall_ssidref(%x) undefined (>max) or unset (0).\n",
+        printkd("%s: ERROR chwall_ssidref(%x) undefined (>max) or unset "
+                "(0).\n",
                 __func__, chwall_ssidp->chwall_ssidref);
         xfree(chwall_ssidp);
         return ACM_INIT_SSID_ERROR;
@@ -118,6 +119,7 @@ static int chwall_init_domain_ssid(void **chwall_ssid, ssidref_t ssidref)
     return ACM_OK;
 }
 
+
 static void chwall_free_domain_ssid(void *chwall_ssid)
 {
     xfree(chwall_ssid);
@@ -205,7 +207,9 @@ chwall_init_state(struct acm_chwall_policy_buffer *chwall_buf,
 
     read_lock(&ssid_list_rwlock);
 
-    /* go through all domains and adjust policy as if this domain was started now */
+    /* go through all domains and adjust policy as if this domain was
+     * started now
+     */
     for_each_acmssid( rawssid )
     {
         chwall_ssid =
@@ -220,8 +224,8 @@ chwall_init_state(struct acm_chwall_policy_buffer *chwall_buf,
 
         /* b) check for conflict */
         for ( i = 0; i < chwall_buf->chwall_max_types; i++ )
-            if (conflict_aggregate_set[i] &&
-                ssidrefs[chwall_ssidref * chwall_buf->chwall_max_types + i])
+            if ( conflict_aggregate_set[i] &&
+                 ssidrefs[chwall_ssidref * chwall_buf->chwall_max_types + i] )
             {
                 printk("%s: CHINESE WALL CONFLICT in type %02x.\n",
                        __func__, i);
@@ -231,37 +235,46 @@ chwall_init_state(struct acm_chwall_policy_buffer *chwall_buf,
 
                 goto out;
             }
+
         /* set violation and break out of the loop */
-        /* c) adapt conflict aggregate set for this domain (notice conflicts) */
+        /* c) adapt conflict aggregate set for this domain
+         *    (notice conflicts)
+         */
         for ( i = 0; i < chwall_buf->chwall_max_conflictsets; i++ )
         {
             int common = 0;
             /* check if conflict_set_i and ssidref have common types */
             for ( j = 0; j < chwall_buf->chwall_max_types; j++ )
-                if (conflict_sets[i * chwall_buf->chwall_max_types + j] &&
-                    ssidrefs[chwall_ssidref *
-                            chwall_buf->chwall_max_types + j])
+                if ( conflict_sets[i * chwall_buf->chwall_max_types + j] &&
+                     ssidrefs[chwall_ssidref *
+                              chwall_buf->chwall_max_types + j] )
                 {
                     common = 1;
                     break;
                 }
-            if (common == 0)
+
+            if ( common == 0 )
                 continue;       /* try next conflict set */
-            /* now add types of the conflict set to conflict_aggregate_set (except types in chwall_ssidref) */
+
+            /* now add types of the conflict set to conflict_aggregate_set
+             * (except types in chwall_ssidref)
+             */
             for ( j = 0; j < chwall_buf->chwall_max_types; j++ )
-                if (conflict_sets[i * chwall_buf->chwall_max_types + j] &&
-                    !ssidrefs[chwall_ssidref *
-                             chwall_buf->chwall_max_types + j])
+                if ( conflict_sets[i * chwall_buf->chwall_max_types + j] &&
+                     !ssidrefs[chwall_ssidref *
+                               chwall_buf->chwall_max_types + j] )
                     conflict_aggregate_set[j]++;
         }
     }
  out:
     read_unlock(&ssid_list_rwlock);
     return violation;
-    /* returning "violation != 0" means that the currently running set of domains would
-     * not be possible if the new policy had been enforced before starting them; for chinese
-     * wall, this means that the new policy includes at least one conflict set of which
-     * more than one type is currently running */
+    /* returning "violation != 0" means that the currently running set of
+     * domains would not be possible if the new policy had been enforced
+     * before starting them; for chinese wall, this means that the new
+     * policy includes at least one conflict set of which more than one
+     * type is currently running
+     */
 }
 
 
@@ -348,8 +361,10 @@ static int _chwall_update_policy(u8 *buf, u32 buf_size, int test_only,
     memset(conflict_aggregate_set, 0,
            sizeof(domaintype_t) * chwall_buf->chwall_max_types);
 
-    /* 3. now re-calculate the state for the new policy based on running domains;
-     *    this can fail if new policy is conflicting with running domains */
+    /* 3. now re-calculate the state for the new policy based on
+     *    running domains; this can fail if new policy is conflicting
+     *    with running domains
+     */
     if ( chwall_init_state(chwall_buf, ssids,
                            conflict_sets, running_types,
                            conflict_aggregate_set,
@@ -483,31 +498,27 @@ static int _chwall_pre_domain_create(void *subject_ssid, ssidref_t ssidref)
 
     chwall_ssidref = GET_SSIDREF(ACM_CHINESE_WALL_POLICY, ssidref);
 
-    if (chwall_ssidref == ACM_DEFAULT_LOCAL_SSID)
-    {
-        printk("%s: ERROR CHWALL SSID is NOT SET but policy enforced.\n",
-               __func__);
-        return ACM_ACCESS_DENIED;       /* catching and indicating config error */
-    }
-
-    if (chwall_ssidref >= chwall_bin_pol.max_ssidrefs)
+    if ( chwall_ssidref >= chwall_bin_pol.max_ssidrefs )
     {
         printk("%s: ERROR chwall_ssidref > max(%x).\n",
                __func__, chwall_bin_pol.max_ssidrefs - 1);
         return ACM_ACCESS_DENIED;
     }
+
     /* A: chinese wall check for conflicts */
-    for (i = 0; i < chwall_bin_pol.max_types; i++)
-        if (chwall_bin_pol.conflict_aggregate_set[i] &&
-            chwall_bin_pol.ssidrefs[chwall_ssidref *
-                                   chwall_bin_pol.max_types + i])
+    for ( i = 0; i < chwall_bin_pol.max_types; i++ )
+        if ( chwall_bin_pol.conflict_aggregate_set[i] &&
+             chwall_bin_pol.ssidrefs[chwall_ssidref *
+                                     chwall_bin_pol.max_types + i] )
         {
             printk("%s: CHINESE WALL CONFLICT in type %02x.\n", __func__, i);
             return ACM_ACCESS_DENIED;
         }
 
     /* B: chinese wall conflict set adjustment (so that other
-     *      other domains simultaneously created are evaluated against this new set)*/
+     *    other domains simultaneously created are evaluated against
+     *    this new set)
+     */
     for ( i = 0; i < chwall_bin_pol.max_conflictsets; i++ )
     {
         int common = 0;
@@ -521,7 +532,7 @@ static int _chwall_pre_domain_create(void *subject_ssid, ssidref_t ssidref)
                 common = 1;
                 break;
             }
-        if (common == 0)
+        if ( common == 0 )
             continue;           /* try next conflict set */
         /* now add types of the conflict set to conflict_aggregate_set (except types in chwall_ssidref) */
         for ( j = 0; j < chwall_bin_pol.max_types; j++ )
@@ -571,9 +582,15 @@ static void _chwall_post_domain_create(domid_t domid, ssidref_t ssidref)
                 common = 1;
                 break;
             }
+
         if ( common == 0 )
-            continue;           /* try next conflict set */
-        /* now add types of the conflict set to conflict_aggregate_set (except types in chwall_ssidref) */
+        {
+            /* try next conflict set */
+            continue;
+        }
+
+        /* now add types of the conflict set to conflict_aggregate_set
+           (except types in chwall_ssidref) */
         for ( j = 0; j < chwall_bin_pol.max_types; j++ )
             if ( chwall_bin_pol.
                  conflict_sets[i * chwall_bin_pol.max_types + j]
@@ -638,9 +655,15 @@ static void chwall_domain_destroy(void *object_ssid, struct domain *d)
                 common = 1;
                 break;
             }
-        if (common == 0)
-            continue;           /* try next conflict set, this one does not include any type of chwall_ssidref */
-        /* now add types of the conflict set to conflict_aggregate_set (except types in chwall_ssidref) */
+        if ( common == 0 )
+        {
+            /* try next conflict set, this one does not include
+               any type of chwall_ssidref */
+            continue;
+        }
+
+        /* now add types of the conflict set to conflict_aggregate_set
+           (except types in chwall_ssidref) */
         for ( j = 0; j < chwall_bin_pol.max_types; j++ )
             if ( chwall_bin_pol.
                  conflict_sets[i * chwall_bin_pol.max_types + j]
index a4fcbd488dbf7216fe4aefaaa170f73a9a49865c..eaeb0a233ba10ac16c7035c6bb12cdbb7bec1903 100644 (file)
@@ -408,7 +408,7 @@ _ste_update_policy(u8 *buf, u32 buf_size, int test_only,
         ste_bin_pol.max_ssidrefs = ste_buf->ste_max_ssidrefs;
         ste_bin_pol.ssidrefs = (domaintype_t *)ssidrefsbuf;
 
-        if ( ste_init_state(NULL) )
+        if ( ste_init_state(errors) )
         {
             /* new policy conflicts with sharing of running domains */
             printk("%s: New policy conflicts with running domains. "